package com.ruoyi.web.core;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.business.base.JoBaseEntity;
import com.ruoyi.business.base.JoEntityEnum;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.controller.system.SysDictDataController;
import com.ruoyi.web.controller.system.SysUserController;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 业务controller基类
 *
 * @author Jyl
 */
public class JoController extends BaseController
{

    @Autowired
    public RedisCache redis;

    @Autowired
    public SysUserController userController;

    @Autowired
    public SysDictDataController sysDictDataController;

    @Autowired
    private ISysUserService sysUserService;

    /**
     * @return 获取当前方法
     */
    protected String logCurrentMethodName()
    {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        // stackTrace[0] 是 getStackTrace 方法
        // stackTrace[1] 是 logCurrentMethodName 方法
        // stackTrace[2] 是调用 logCurrentMethodName 的方法（即当前方法）
        return stackTrace[2].getMethodName();
    }

    /**
     * 获取当前用户
     */
    protected SysUser getUser()
    {
        return getLoginUser().getUser();
    }

    /**
     * 获取 当前用户 角色集合
     */
    protected List<Long> getRoleIds()
    {
        List<SysRole> list = getUser().getRoles();
        if (StringUtils.isEmpty(list))
        {
            return new ArrayList<>();
        }

        List<Long> ids = new ArrayList();
        for (SysRole role : list)
        {
            ids.add(role.getRoleId());
        }
        return ids;
    }

    /**
     * 是否有这个角色
     *
     * @param roleIds 角色集合
     * @param roleId  目标角色
     * @return 执行结果
     */
    protected boolean isRoleId(List<Long> roleIds, Long roleId)
    {
        return roleIds.contains(roleId);
    }

    protected boolean isRoleId(Long roleId)
    {
        return isRoleId(getRoleIds(), roleId);
    }

    protected boolean otherRoleId(Long roleId)
    {
        return otherRoleId(getRoleIds(), roleId);
    }

    /**
     * 是否有其他角色
     *
     * @param roleIds 角色集合
     * @param roleId  目标角色
     * @return 执行结果
     */
    protected boolean otherRoleId(List<Long> roleIds, Long roleId)
    {
        int i = 0;
        for (Long id : roleIds)
        {
            if (id != roleId)
            {
                i++;
            }
        }
        return i > 0;
    }

    /**
     * 获取当前用户昵称
     */
    protected String getNickName()
    {
        return getUser().getNickName();
    }

    /**
     * vo转换
     */
    protected <E> JSONArray toVO(List list, Class<E> e)
    {
        return new JSONArray(BeanUtil.copyToList(list, e));
    }

    /**
     * 获取删除数据 ids
     *
     * @param list
     * @param <E>
     * @return
     */
    protected <E extends JoBaseEntity> List<Long> getDelFlagIds(List<E> list)
    {
        List<Long> ids = new ArrayList<>();
        for (E entity : list)
        {
            if (StringUtils.isNotEmpty(entity.getDelFlag())
                && JoEntityEnum.DELETEON.equals(entity.getDelFlag())
                && StringUtils.isNotNull(entity.getId())
            )
            {
                ids.add(entity.getId());
            }
        }
        return ids;
    }

    /**
     * IPage 对象转换
     *
     * @param iPage
     * @param clazz
     * @param <R>
     * @return
     */
    protected <R> IPage<R> convert(IPage iPage, Class<R> clazz)
    {
        return iPage.convert(e ->
        {
            R result = null;
            try
            {
                result = clazz.newInstance();
            } catch (InstantiationException ex)
            {
                throw new RuntimeException(ex);
            } catch (IllegalAccessException ex)
            {
                throw new RuntimeException(ex);
            }
            BeanUtils.copyProperties(e, result);
            return result;
        });
    }

    /**
     * 组装映射数据
     *
     * @param k    key
     * @param v    value
     * @param list 数据源
     * @param <R>  数据泛型
     * @return
     */
    @SneakyThrows
    protected <R> Map kv(String k, String v, List<R> list)
    {
        Map map = new HashMap();
        for (R o : list)
        {
            Method getK = o.getClass().getMethod(getMethod(k));
            Method getv = o.getClass().getMethod(getMethod(v));
            map.put(getK.invoke(o), getv.invoke(o));
        }
        return map;
    }

    /**
     * @param ids 用户主键
     * @return 用户主键映射
     */
    protected Map<Long, SysUser> mapUser(List<Long> ids)
    {
        Map map = new HashMap();
        List<SysUser> list = sysUserService.listIds(ids);
        for (SysUser sysUser : list)
        {
            map.put(sysUser.getUserId(), sysUser);
        }
        return map;
    }

    /**
     * @param userId 用户主键
     * @return 系统用户
     */
    protected SysUser findUserById(Long userId)
    {
        return sysUserService.selectUserById(userId);
    }

    /**
     * 提取源数据
     *
     * @param vo  源数据
     * @param <R>
     * @return
     */
    protected <R> List<Long> ids(IPage<R> vo, String cl) throws NoSuchMethodException,
            InvocationTargetException, IllegalAccessException
    {
        return ids(vo.getRecords(), cl);
    }

    /**
     * 提取源数据
     *
     * @param vo  源数据
     * @param cl  对象字段
     * @param <R>
     * @return
     */
    protected <R> List<Long> ids(List<R> vo, String cl) throws NoSuchMethodException,
            InvocationTargetException, IllegalAccessException
    {
        Set<Long> ids = new HashSet<>();
        for (R record : vo)
        {
            Method method = record.getClass().getMethod(getMethod(cl));
            method.invoke(record);
            Long id = (Long) method.invoke(record);
            if (ObjectUtils.isNotEmpty(id))
            {
                ids.add(id);
            }
        }
        return ids.stream().collect(Collectors.toList());
    }

    /**
     * 组装get方法名
     *
     * @param k
     * @return
     */
    public String getMethod(String k)
    {
        return "get" + k.substring(0, 1).toUpperCase() + k.substring(1);
    }

    /**
     * 组装set方法名
     *
     * @param k
     * @return
     */
    public String setMethod(String k)
    {
        return "set" + k.substring(0, 1).toUpperCase() + k.substring(1);
    }

    /**
     * 数据映射
     *
     * @param vo    源数据
     * @param ydid  源主键名称
     * @param ydKey 源目标名称
     * @param <R>
     */
    @SneakyThrows
    protected <R> void toKey(
            IPage<R> vo,
            Map map,
            String ydid,
            String ydKey)
    {
        toKey(vo.getRecords(), map, ydid, ydKey);
    }

    /**
     * 数据映射
     *
     * @param vo    源数据
     * @param ydid  源主键名称
     * @param ydKey 源目标名称
     * @param <R>
     */
    @SneakyThrows
    protected <R> void toKey(
            List<R> vo,
            Map map,
            String ydid,
            String ydKey)
    {
        for (R record : vo)
        {
            Method get = record.getClass().getMethod(getMethod(ydid));
            Method set = record.getClass().getMethod(setMethod(ydKey),
                    record.getClass().getDeclaredField(ydKey).getType());

            set.invoke(record, map.get(get.invoke(record)));
        }
    }


    /**
     * 设置默认登录用户信息，用于开放接口
     */
    public void setDefaultLoginInfo()
    {
        setDefaultLoginInfo(new SysUser());
    }

    /**
     * 设置默认登录用户信息，用于开放接口
     */
    public void setDefaultLoginInfo(SysUser sysUser)
    {
        sysUser.setUserId(ObjectUtils.isEmpty(sysUser.getUserId())
                ? -666l : sysUser.getUserId());
        sysUser.setNickName("缺省权限");
        sysUser.setUserName("缺省权限");

        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(sysUser.getUserId());
        loginUser.setUser(sysUser);
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    }
}
